#include "/project/public/_public.h"

//程序运行的日志
CLogFile logfile;


int main(int argc,char* argv[])
{
	//程序的帮助文档
	if(argc != 2)
	{
		printf("\n");
		printf("Using:./checkproc logfilename\n");
		printf("Example:/project/tools1/bin/procctl 10 /project/tools1/bin/checkproc /tmp/log/checkproc.log\n\n");
		printf("本程序用于检查后台服务程序是否超时,如果已经超时,就终止他\n");
		printf("注意:\n");
		printf("	1) 本程序由procctl启动,运行周期建议为10秒\n");
		printf("	2) 为了避免被普通用户误杀,本程序应该用root用户启动.\n\n\n");
		printf("	3) 如果停止本程序只能用kill -9强制终止");
		return -1;
	}

	//关闭全部的信号
	CloseIOAndSignal(true);
	//打开日志文件
	if(false == logfile.Open(argv[1]))
	{
		printf("logfile.Open(%s) failed",argv[1]);
		return -1;
	}
	//创建/获取共享内存
	int shmid = 0;
	if((shmid = shmget((key_t)SHMKEYP,MAXNUMP*sizeof(struct st_procinfo),0666|IPC_CREAT)) == -1)
	{
		logfile.Write("创建/获取共享内存(%x)失败.\n",SHMKEYP);
		return -1;
	}
	//将共享内存连接到当前进程的地址空间
	struct st_procinfo* shm = (struct st_procinfo*)shmat(shmid,0,0);

	//遍历共享内存中的全部记录
	for(int i = 0; i < MAXNUMP; ++i)
	{
		//如果记录的pid==0,表示空记录,continue;
		if(shm[i].pid == 0)
			continue;
		//如果记录的pid!=0,表示是服务程序的心跳记录,写个日志
		//logfile.Write("i = %d,pid = %d, pname = %s,timeout = %d,atime=%d\n",i,shm[i].pid,shm[i].pname,shm[i].timeout,shm[i].atime);
		//向进程发送信号0,判断它是否还存在,如果不存在,从共享内存中删除该记录,continue
		int iret = kill(shm[i].pid,0);
		if(-1 == iret)
		{
			logfile.Write("进程pid=%d(%s)已经不存在 \n",shm[i].pid,shm[i].pname);
			memset(shm+i,0,sizeof(struct st_procinfo));
			continue;
		}
		//进程存在检查是否超时,未超时continue
		time_t now = time(NULL);
		if((now-shm[i].atime) < shm[i].timeout)
			continue;
		//如果已超时
		
		logfile.Write("进程pid=%d(%s)已经超时 \n",shm[i].pid,shm[i].pname);
		//发送信号15,尝试正常终止进程
		kill(shm[i].pid,15);
		//服务程序退出需要时间,一般5秒内可以完成,我们每一秒判断一次进程是否退出,累计5秒
		for(int i = 0; i < 5; ++i)
		{
			sleep(1);
			iret = kill(shm[i].pid,0);
			if(-1 == iret)
				break;
		}
		//如果进程仍然存在,发送信号9,强制终止它
		if(-1 == iret)
		{
			
			logfile.Write("进程pid=%d(%s)已经正常杀死 \n",shm[i].pid,shm[i].pname);
		}
		else
		{
			kill(shm[i].pid,9);
			logfile.Write("进程pid=%d(%s)已经强制杀死 \n",shm[i].pid,shm[i].pname);

		}
		//从共享内存中删除已超时进程的心跳记录
		memset(shm+i,0,sizeof(struct st_procinfo));
		
	}

	//把共享内存从当前进程中分离
	shmdt(shm);

	return 0;
}
